/**
 * Copyright 2018-2019 jianggujin (www.jianggujin.com).
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jianggujin.modulelink.support.refresh;

import java.util.List;
import java.util.Set;

import com.jianggujin.modulelink.config.JMultiVersionModuleConfig;
import com.jianggujin.modulelink.magager.JMultiVersionModuleManager;
import com.jianggujin.modulelink.module.JModule;
import com.jianggujin.modulelink.util.JAssert;
import com.jianggujin.modulelink.util.JDefaultMultiValueMap;
import com.jianggujin.modulelink.util.JLogFactory;
import com.jianggujin.modulelink.util.JLogFactory.JLog;
import com.jianggujin.modulelink.util.JMultiValueMap;

/**
 * 刷新模块的抽象实现
 * 
 * @author jianggujin
 *
 */
public abstract class JAbstractMultiVersionModuleRefresh implements JModuleRefresh {
    private final JLog logger = JLogFactory.getLog(JAbstractMultiVersionModuleRefresh.class);
    protected final JMultiVersionModuleManager moduleManager;

    protected JAbstractMultiVersionModuleRefresh(JMultiVersionModuleManager moduleManager) {
        JAssert.checkNotNull(moduleManager, "moduleManager must not be null.");
        this.moduleManager = moduleManager;
    }

    /**
     * 刷新
     */
    @Override
    public synchronized void refreshModuleConfigs() {
        // 查询到的模块配置信息
        Set<JMultiVersionModuleConfig> queryConfigs = queryModuleConfigs();
        JMultiValueMap<String, String> moduleVersions = filterModuleConfigs(queryConfigs);
        // 查询模块为空，卸载所有
        if (queryConfigs == null || queryConfigs.isEmpty()) {
            this.moduleManager.unload();
            return;
        }
        // 先卸载模块，然后加载模块
        // 卸载
        for (JModule<JMultiVersionModuleConfig> module : this.moduleManager.getModules()) {
            JMultiVersionModuleConfig moduleConfig = (JMultiVersionModuleConfig) module.getModuleConfig();
            String moduleName = moduleConfig.getModuleName();
            String version = moduleConfig.getVersion();
            if (moduleVersions.containsKey(moduleName)) {
                List<String> versions = moduleVersions.get(moduleName);
                // 不存在，则需要卸载
                if (!versions.contains(version)) {
                    try {
                        this.moduleManager.unload(moduleName, version);
                    } catch (Exception e) {
                        logger.error("unload module error.", e);
                    }
                }
            } else {
                try {
                    this.moduleManager.unload(moduleName);
                } catch (Exception e) {
                    logger.error("unload module error.", e);
                }
            }
        }

        // 加载
        for (JMultiVersionModuleConfig moduleConfig : queryConfigs) {
            try {
                this.moduleManager.load(moduleConfig);
            } catch (Exception e) {
                logger.error("load module error.", e);
            }
        }
    }

    /**
     * 过滤模块配置
     * 
     * @param moduleConfigs 查询到的模块
     * @return 模块版本
     */
    protected JMultiValueMap<String, String> filterModuleConfigs(Set<JMultiVersionModuleConfig> moduleConfigs) {
        if (moduleConfigs == null) {
            return null;
        }

        JMultiValueMap<String, String> queryVersions = new JDefaultMultiValueMap<String, String>();

        for (JMultiVersionModuleConfig moduleConfig : moduleConfigs) {
            queryVersions.add(moduleConfig.getModuleName(), moduleConfig.getVersion());
        }
        return queryVersions;
    }

    /**
     * 查询所有模块配置信息
     *
     * @return 模块配置信息
     */
    protected abstract Set<JMultiVersionModuleConfig> queryModuleConfigs();

}
